#!/usr/bin/env python
# -*- coding: utf-8 -*-
# piwati is PIcasa Web Album Tag Import :-)
# update / insert /delete TAG

import piwalog
logger = piwalog.logging.getLogger("piwati")
logger.info(u'start')

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

import locale
console_encode = locale.getpreferredencoding()
logger.debug(u"console_encode=[%s]"%console_encode)

import codecs
import re

from optparse import OptionParser
from getpass import getpass
from xml.etree.ElementTree import *

import gdata.photos.service
import gdata.media
import gdata.geo

from piwacommon import *
import dsv

re_photo_id_only = re.compile("^(\d+)$")
re_photo_id = re.compile("/photoid/(\d+)$")

# parse options ...
parser = OptionParser(usage="%prog -u [-p] [-o] -t", version="%prog 0.0")
parser.add_option("-u", "--uid",  dest="uid",
                  help="login user id", default="", metavar="UID")
parser.add_option("-p", "--passwd",  dest="passwd",
                  help="login user password", default="", metavar="PASSWORD")
parser.add_option("-o", "--album-owner", dest="owner",
                  help="album owner", default="", metavar="OWNER")
parser.add_option('-t', '--tag', dest='tag_file',
                  help='input filename for tag.', default="", metavar="FILENAME")
(options, args) = parser.parse_args()

if options.tag_file == '' :
    parser.error("specify import tag filename.\n")

if options.uid != '' :
    if options.passwd == '' :
        options.passwd = getpass("login password:")
    if options.owner == '':
        options.owner = options.uid.split('@')[0]
else :
    parser.error("specify userid and password.\n")

#get photo service object and login
gd_client = gdata.photos.service.PhotosService()
gd_client.source = options.owner
gd_client.email = options.uid
gd_client.password = options.passwd
try :
    import socket   # for socket.gaierror
    gd_client.ProgrammaticLogin()
except gdata.service.BadAuthentication :
    logger.error(u"gdata.service.BadAuthentication")
    sys.stderr.write(u"Invalid user-id (-u) or password\n".encode(console_encode))
    sys.exit()
except socket.gaierror, (errno, errstr):
        logger.error(u"socket.gaierror:(%s):%s"%(errno,errstr))
        sys.stderr.write((u"maybe cannot access internet. (socket.gaierror:(%s):%s)\n"%(errno,errstr)).encode(console_encode))
        sys.exit()

dsv = dsv.DSV(FIXED_TITLE)

tag_fd = codecs.open(options.tag_file, 'r', encoding=TAG_ENCODE)
buf = tag_fd.readline()
if buf != '' :
    #check title line...
    line = buf.rstrip()
    dsv.split(line, quote='"')
    for key in FIXED_TITLE :
        if dsv.fixed[key] != key :
            logger.critical(u"fatal: unknown fixed columns %s (excepted %s"%(u','.join(FIXED_TITLE), u','.join(dsv.fixed.keys())))
            sys.stderr.write((u"fatal: unknown fixed columns %s (excepted %s"%(u','.join(FIXED_TITLE), u','.join(dsv.fixed.keys()))).encode(console_encode))
            sys.exit()

    srcPhotoDic = {}
    lastDsvAlbumId = None
    
    for buf in tag_fd :
        update_flag = False
        
        line = buf.rstrip()     # delete tail whitespaces ( '\t\n\x0b\x0c\r ' ) 末尾の\tも削られてしまうが、実用上問題ない。
        
        dsv.split(line, quote='"')

        #album_idごとにまとまってると仮定し、album_idが変わるたびにsrcPhotoDicをクリア。 まとまってない場合でも遅くはなるが動く
        if lastDsvAlbumId != dsv.fixed['album_id']:
            srcPhotoDic = {}
        lastDsvAlbumId = dsv.fixed['album_id']
        
        #match photo_id
        if not (dsv.fixed['photo_id'] in srcPhotoDic) : # check cache .... 
            sys.stderr.write((u"read photos meta data for matching from web album:%s(%s) ...\n"%(dsv.fixed['album_title'], dsv.fixed['album_id'])).encode(console_encode))
            srcPhotos = gd_client.GetFeed(
                '/data/feed/api/user/%s/albumid/%s?kind=photo' % (
                    options.owner, dsv.fixed['album_id']))
            for srcPhoto in srcPhotos.entry :
                srcPhotoId = uni(srcPhoto.id.text, GDATA_ENCODE)
                srcPhotoId = srcPhotoId[srcPhotoId.index(u'/photoid/')+len(u'/photoid/'):]      # /photoid/ の 後ろ全部を取得
                logger.debug("srcPhotoId=%s"%srcPhotoId)
                srcPhotoDic[srcPhotoId] = {'photo':srcPhoto, 'tag':set() }
                tag_feed_uri ='/data/feed/api/user/%s/albumid/%s/photoid/%s?kind=tag'%(options.owner,
                                                                                       srcPhoto.albumid.text,
                                                                                       srcPhotoId.encode(GDATA_ENCODE))
                logger.debug("tag_feed_uri:%s"%tag_feed_uri)
                photo_tags = gd_client.GetFeed(tag_feed_uri)
                for srcPhotoTag in photo_tags.entry:
                    if srcPhotoTag.title.text != None :
                        srcPhotoDic[srcPhotoId]['tag'].add(uni(srcPhotoTag.title.text, GDATA_ENCODE))
                    
               
            if not (dsv.fixed['photo_id'] in srcPhotoDic) :                # 取得したけど見つからねぇぞゴルァ
                logger.error(u"photo_id=%s;not include feed."%dsv.fixed['photo_id'])
                sys.stderr.write((u"photo_id=%s:not include feed"%dsv.fixed['photo_id']).encode(console_encode))
                continue
        
        logger.debug(u"srcPhotoDic:%s"%str(srcPhotoDic))

        entry = gdata.photos.PhotoEntry()
        entry.link = srcPhotoDic[dsv.fixed['photo_id']]['photo'].link
          
        # checking photo title
        srcPhotoTitle = uni(srcPhotoDic[dsv.fixed['photo_id']]['photo'].title.text, GDATA_ENCODE)
        logger.debug(u"photo_title=%s;%s"%(srcPhotoTitle, dsv.fixed['photo_title']))
        if srcPhotoTitle != dsv.fixed['photo_title'] :
            if not entry.title :
                entry.title = gdata.atom.Title()
            entry.title.text = dsv.fixed['photo_title'].encode(GDATA_ENCODE)
            logger.debug(u"photo_id=%s;title changed;%s to %s\n"%(dsv.fixed['photo_id'], srcPhotoTitle, dsv.fixed['photo_title']))
            sys.stderr.write((u"photo title changed;%s to %s\n"%(srcPhotoTitle, dsv.fixed['photo_title']).encode(console_encode)))
            update_flag = True

        # cecking tag
        dsttag = set(dsv.var)
        if u'' in dsttag :
            dsttag.remove(u'')
        if None in dsttag :
            dsttag.remove(None)
        logger.debug(u"srctag:")
        logger.debug(srcPhotoDic[dsv.fixed['photo_id']]['tag'])
        logger.debug(u"dsttag:")
        logger.debug(str(dsttag))
                         
        if srcPhotoDic[dsv.fixed['photo_id']]['tag'] != dsttag :    #集合型同士の比較
            if not entry.media :
                entry.media = gdata.media.Group()
            if not entry.media.keywords :
                entry.media.keywords = gdata.media.Keywords()
            #entry.media.keywords.text = (u','.join(dsttag)).encode(GDATA_ENCODE)
            entry.media.keywords.text = (u','.join(dsttag))
            logger.debug(u"photo_id=%s;tag changed"%dsv.fixed['photo_id'])
            sys.stderr.write((u"photo tag changed\n").encode(console_encode))
            update_flag = True

        # 最終的に更新物があれば更新
        if update_flag :
            updated_entry = gd_client.UpdatePhotoMetadata(entry)
            logger.debug(u"%s:%s:update."%(dsv.fixed['album_title'],dsv.fixed['photo_title']))
            sys.stderr.write((u"%s:%s:updated.\n"%(dsv.fixed['album_title'],dsv.fixed['photo_title'])).encode(console_encode))
        else :
            logger.debug(u"%s:%s:nothing update."%(dsv.fixed['album_title'],dsv.fixed['photo_title']))
            sys.stderr.write((u"%s:%s:nothing updated.\n"%(dsv.fixed['album_title'],dsv.fixed['photo_title'])).encode(console_encode))

tag_fd.close()
logger.debug(u"done.")
sys.stderr.write(u"done.\n".encode(console_encode))
